﻿/************************************
 * 作者：eric.cao
 * 
 * 该类名称：数据格式转换类
 * 
 * *********************************/
using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Reflection;
using System.IO;
using System.ComponentModel;
using BaseSet.Entity.Common.Text;
using System.Text.RegularExpressions;
using System.Xml;
using System.Drawing;
using System.Data.SqlClient;

namespace BaseSet.Entity.Common.DataOperation
{
    /// <summary>
    /// 数据结构转换
    /// </summary>
    public class DataConvert
    {
        /// <summary>
        /// DataTable转换为List
        /// </summary>
        /// <typeparam name="T">泛型</typeparam>
        /// <param name="dt">DataTable</param>
        /// <returns>返回泛型类型</returns>
        public static IList<T> DataTableToList<T>(DataTable dt)
        {
            IList<T> list = new List<T>();

            if (dt == null)
            {
                return list;
            }

            for (int i = 0; i < dt.Rows.Count; i++)
            {
                T t = System.Activator.CreateInstance<T>();
                Type obj = t.GetType();
                // 循环字段
                for (int j = 0; j < dt.Columns.Count; j++)
                {
                    object tempValue = null;

                    if (dt.Rows[i][j] != System.DBNull.Value)
                    {
                        tempValue = dt.Rows[i][j];
                        Tools.SetPropertyValue(t, dt.Columns[j].ColumnName, tempValue);
                    }
                }

                list.Add(t);
            }
            return list;
        }

        /// <summary>
        /// List转换成DataTable
        /// </summary>
        /// <param name="list">要转化的Ilist</param>
        /// <returns>转化后的Dataset</returns>
        public static DataTable ListToDataTable<T>(IList<T> i_objlist)
        {
            if (i_objlist == null || i_objlist.Count <= 0)
            {
                return null;
            }

            DataTable dt = new DataTable(typeof(T).Name);
            DataColumn column;
            DataRow row;

            PropertyInfo[] myPropertyInfo = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);

            foreach (T t in i_objlist)
            {
                if (t == null)
                {
                    continue;
                }

                row = dt.NewRow();

                for (int i = 0, j = myPropertyInfo.Length; i < j; i++)
                {
                    System.Reflection.PropertyInfo pi = myPropertyInfo[i];

                    string name = pi.Name;

                    if (dt.Columns[name] == null)
                    {
                        column = new DataColumn(name, pi.PropertyType);
                        dt.Columns.Add(column);
                    }

                    row[name] = pi.GetValue(t, null);
                }

                dt.Rows.Add(row);
            }

            return dt;
        }

        /// <summary>
        /// 将枚举类型转换为DataTable
        /// </summary>
        /// <param name="enumType">内容</param>
        /// <returns>DataTable:转换结果</returns>
        public static DataTable EnumToTable(Type enumType)
        {
            if (enumType.IsEnum != true)
            {
                throw new InvalidOperationException();
            }

            DataTable dt = new DataTable();
            dt.Columns.Add("Text", typeof(System.String));
            dt.Columns.Add("Content", typeof(System.String));
            dt.Columns.Add("Value", typeof(System.Int32));

            Type typeDescription = typeof(DescriptionAttribute);

            FieldInfo[] fields = enumType.GetFields();

            foreach (FieldInfo field in fields)
            {
                if (field.FieldType.IsEnum == true)
                {
                    DataRow dr = dt.NewRow();

                    dr["Content"] = field.Name;
                    dr["Value"] = (int)enumType.InvokeMember(field.Name, BindingFlags.GetField, null, null, null);

                    object[] arr = field.GetCustomAttributes(typeDescription, true);
                    if (arr.Length > 0)
                    {
                        DescriptionAttribute aa = (DescriptionAttribute)arr[0];
                        dr["Text"] = aa.Description;
                    }
                    else
                    {
                        dr["Text"] = field.Name;
                    }
                    dt.Rows.Add(dr);
                }
            }

            return dt;
        }

        /// <summary>
        /// 把数组转换成字符串 需测试
        /// </summary>
        /// <param name="s_array">数组</param>
        /// <param name="SeparateChar">分隔符</param>
        /// <returns>转换后的字符串</returns>
        public static string ArrayToString(string[] s_array, string SeparateChar)
        {
            StringBuilder builder = new StringBuilder();
            foreach (string str in s_array)
            {
                builder.Append(str);
                builder.Append(SeparateChar);
            }
            return Regex.Replace(builder.ToString(), SeparateChar + "$", string.Empty);
        }

        /// <summary>
        /// 将TimeSpan转换为字符串 需改进
        /// </summary>
        /// <param name="Time">时间间隔</param>
        /// <param name="haveSeconds">有秒就为true,没有秒就为false</param>
        /// <param name="haveMilliseconds">有毫秒就为true,没有毫秒就为false</param>
        /// <returns>转换后的时间字符串</returns>
        public static string SwitchTimeSpan(TimeSpan Time, bool haveSeconds, bool haveMilliseconds)
        {
            return Time.Hours.ToString("D2") + ":" + Time.Minutes.ToString("D2")
                + (haveSeconds ? (":" + Time.Seconds.ToString("D2")
                + (haveMilliseconds ? ("." + Time.Milliseconds.ToString().Substring(0, 1)) : "")) : "");
        }

        /// <summary>
        /// 将stream类型转换成bytes[]数组
        /// </summary>
        /// <param name="stream">stream类型数据</param>
        /// <returns>byte[]数组</returns>
        public static byte[] StreamToBytes(Stream stream)
        {
            byte[] bytes = new byte[stream.Length];
            stream.Read(bytes, 0, bytes.Length);
            stream.Seek(0, SeekOrigin.Begin);
            return bytes;
        }

        /// <summary>
        /// 根据数据类型得到数据库类型
        /// </summary>
        /// <param name="dataType"></param>
        /// <returns></returns>
        public static object GetSqlDbTypeByDataType(string dataType)
        {
            dataType = dataType.ToLower();

            if (dataType == DataType.String)
            {
                return SqlDbType.NVarChar;
            }
            else if (dataType == DataType.Int16)
            {
                return SqlDbType.SmallInt;
            }
            else if (dataType == DataType.Int32)
            {
                return SqlDbType.Int;
            }
            else if (dataType == DataType.Int64)
            {
                return SqlDbType.BigInt;
            }
            else if (dataType == DataType.Boolean)
            {
                return SqlDbType.Bit;
            }
            else if (dataType == DataType.DateTime)
            {
                return SqlDbType.DateTime;
            }
            else if (dataType == DataType.Double)
            {
                return SqlDbType.Float;
            }
            else
            {
                return SqlDbType.Variant;
            }
        }

        //public static void OOO<T,R>()
        //{
        //    Converter<T, R> aaa = new Converter<T, R>();
        //    aaa.Method
        //}

        /// <summary>
        /// 将XML文档转换为Object
        /// </summary>
        /// <param name="xd">Xml文档 除根节点外 只能有一级结构</param>
        /// <returns></returns>
        public static T XmlToObject<T>(XmlDocument xd)
        {
            if (xd == null)
            {
                return default(T);
            }

            XmlElement root = xd.DocumentElement;
            if (root.ChildNodes.Count == 0)
            {
                return default(T);
            }

            //取类型的所有属性
            string[] fields = Tools.GetPropertyNames<T>();
            if (fields.Length == 0)
            {
                return default(T);
            }

            T obj = System.Activator.CreateInstance<T>();
            object tempValue;
            for (int j = 0; j < fields.Length; j++)
            {
                tempValue = root.SelectSingleNode(fields[j]).InnerText;
                Tools.SetPropertyValue(obj, fields[j], tempValue);
            }

            return obj;
        }

        /// <summary>
        /// 将XmlNodeList转换为List＜T＞
        /// </summary>
        /// <param name="nodes">Xml文档 除根节点外 只能有两级结构</param>
        /// <returns></returns>
        public static IList<T> XmlToList<T>(XmlNodeList nodes)
        {
            if (nodes == null || nodes.Count == 0)
            {
                return null;
            }

            //取类型的所有属性
            string[] fields = Tools.GetPropertyNames<T>();
            if (fields.Length == 0)
            {
                return null;
            }

            IList<T> list = new List<T>();
            T obj;
            object tempValue;
            for (int i = 0; i < nodes.Count; i++)
            {
                if (nodes[i].NodeType != XmlNodeType.Element)
                {
                    continue;
                }
                obj = System.Activator.CreateInstance<T>();
                for (int j = 0; j < fields.Length; j++)
                {
                    tempValue = nodes[i].SelectSingleNode(fields[j]).InnerText;
                    Tools.SetPropertyValue(obj, fields[j], tempValue);
                }
                list.Add(obj);
            }
            return list;
        }

        /// <summary>
        ///  将形如 #BFBFBF 的颜色代码转成颜色
        /// </summary>
        /// <param name="code"></param>
        /// <returns></returns>
        public static Color GetColorFromCode(string code)
        {
            int r = 0;
            int g = 0;
            int b = 0;
            code = code.TrimStart('#');

            //&& code.Any(tmpChar => tmpChar > 'A' && tmpChar < 'F')//正则
            if (!string.IsNullOrEmpty(code) && code.Length == 6)
            {
                r = Convert.ToInt32(code.Substring(0, 2), 16);
                g = Convert.ToInt32(code.Substring(2, 2), 16);
                b = Convert.ToInt32(code.Substring(4, 2), 16);

                return Color.FromArgb(r, g, b);
            }

            return Color.Transparent;
        }

        /// <summary>
        /// 从一个 SqlDataReader 中提取一个实体
        /// </summary>
        /// <typeparam name="T">实体类型</typeparam>
        /// <param name="rdr">SqlDataReader</param>
        /// <returns></returns>
        public static T DataReaderToObj<T>(SqlDataReader rdr)
        {
            if (rdr == null)
            {
                return default(T);
            }

            T obj = System.Activator.CreateInstance<T>();

            if (rdr.Read())
            {
                for (int i = 0; i < rdr.FieldCount; i++)
                {
                    object tempValue = default(T);

                    if (!rdr.IsDBNull(i))
                    {
                        tempValue = rdr.GetValue(i);
                        Tools.SetPropertyValue(obj, rdr.GetName(i), tempValue);
                    }
                }

                if (!rdr.IsClosed)
                {
                    rdr.Close();
                    rdr.Dispose();
                }

                return obj;
            }

            return default(T);
        }

        /// <summary>
        /// 从一个 SqlDataReader 中提取实体集
        /// </summary>
        /// <typeparam name="T">实体类型</typeparam>
        /// <param name="rdr">SqlDataReader</param>
        /// <returns></returns>
        public static IList<T> DataReaderToList<T>(SqlDataReader rdr)
        {
            IList<T> list = new List<T>();
            if (rdr == null)
            {
                return list;
            }
            if (!rdr.HasRows)
            {
                if (!rdr.IsClosed)
                {
                    rdr.Close();
                    rdr.Dispose();
                }
                return list;
            }

            T obj = default(T);
            while (rdr.Read())
            {
                obj = System.Activator.CreateInstance<T>();
                for (int i = 0; i < rdr.FieldCount; i++)
                {
                    object tempValue = default(T);

                    if (!rdr.IsDBNull(i))
                    {
                        tempValue = rdr.GetValue(i);
                        Tools.SetPropertyValue(obj, rdr.GetName(i), tempValue);
                    }
                }
                list.Add(obj);
            }

            if (!rdr.IsClosed)
            {
                rdr.Close();
                rdr.Dispose();
            }

            return list;
        }

        /// <summary>
        /// 从一个SqlDataReader中提取 未实现 考虑效率问题
        /// </summary>
        /// <typeparam name="TKey"></typeparam>
        /// <typeparam name="TValue"></typeparam>
        /// <param name="rdr"></param>
        /// <param name="keyField"></param>
        /// <param name="valueField"></param>
        /// <returns></returns>
        internal static Dictionary<TKey, TValue> DataReaderToDic<TKey, TValue>(SqlDataReader rdr, string keyField, string valueField)
        {
            return null;
        }

        /// <summary>
        /// 讲一个整形数组 转换为一个字符串数组
        /// </summary>
        /// <param name="arr"></param>
        /// <returns></returns>
        public static string[] ToStringArr(int[] arr)
        {
            // 定义转换器 从整形到字符型的转换规则
            Converter<int, string> converter = new Converter<int, string>(delegate(int i) { return i.ToString(); });
            string[] result = Array.ConvertAll<int, string>(arr, converter);
            return result;
        }

        /// <summary>
        /// 将一个角色转换成一个用户
        /// 这个方法并没有实际意义 只是为了说明ChangeToAnyType的使用方式
        /// </summary>
        /// <typeparam name="RoleInfo"></typeparam>
        /// <typeparam name="UserInfo"></typeparam>
        /// <param name="role"></param>
        /// <returns></returns>
        private static UserInfo ChgRoleToUser<RoleInfo, UserInfo>(RoleInfo role)
        {
            // 定义转换器 从整形到字符型的转换规则
            Converter<RoleInfo, UserInfo> converter = new Converter<RoleInfo, UserInfo>(
                delegate(RoleInfo r)
                {
                    UserInfo user = System.Activator.CreateInstance<UserInfo>(); //new UserInfo();// 具体的类转换时 可以用new
                    //user.UserID = r.RoleID;
                    //user.UserName = r.RoleName;
                    return user;
                });

            return ChangeToAnyType(role, converter);
        }

        /// <summary>
        /// 将任意输入类型转换为任意输出类型 外部提供转换规则（转换器）
        /// 转换器写法 Converter＜I, O＞ converter = new Converter＜I, O＞(delegate(I iobj) { return default(O); });
        /// </summary>
        /// <typeparam name="I"></typeparam>
        /// <typeparam name="O"></typeparam>
        /// <param name="input"></param>
        /// <returns></returns>
        private static O ChangeToAnyType<I, O>(I input, Converter<I, O> converter)
        {
            O output = converter.Invoke(input);
            return output;
        }
        // 从任意类型的列表 输出任意其他类型的列表 外部提供转换规则（转换器） 未测试
        private static IList<O> GetListUseChgType<I, O>(IList<I> inputList, Converter<I, O> converter)
        {
            IList<O> outputList = new List<O>();
            O output = default(O);
            for (int i = 0; i < inputList.Count; i++)
            {
                output = ChangeToAnyType<I, O>(inputList[i], converter);
                outputList.Add(output);
            }
            return outputList;
        }
    }
}

